from .dataauth import *
from .posutil import _tag_name, _parse_cn
import logging
import tomlkit
import os


logging.getLogger().disabled = True
logging.basicConfig(level=logging.DEBUG)

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.propagate = False
log_fmt = logging.Formatter('%(asctime)s %(name)s %(levelname)-8s %(message)s')
log_file = logging.FileHandler('offcard.log', 'w', encoding='utf-8')
log_file.setFormatter(log_fmt)
logger.addHandler(log_file)
log_console = logging.StreamHandler()
log_console.setFormatter(log_fmt)
logger.addHandler(log_console)


def _get_data_item(data_set, tag: bytes):
    return bytes.fromhex(data_set[_tag_name(tag)])


def _in_data_set(data_set, tag: bytes):
    return _tag_name(tag) in data_set


def offcard_verify(data_file_name='pos-process.toml'):
    with open(data_file_name, 'r', encoding='utf-8') as fp:
        offcard_data = tomlkit.load(fp)

    afl_data = offcard_data['AFL']['DATA']
    gpo_resp = offcard_data['GPO']['DATA']
    gpo_pdol = offcard_data['GPO']['PDOL']

    # 恢复发卡行证书
    logger.debug("========恢复发卡行证书========")
    tag_8f = _get_data_item(afl_data, b'\x8f')  # CA公钥索引
    tag_90 = _get_data_item(afl_data, b'\x90')  # 发卡行公钥证书
    tag_92 = _get_data_item(afl_data, b'\x92') if _in_data_set(afl_data, b'\x92') else None  # 发卡行RSA公钥余数
    if tag_92 and len(tag_92) == 0:
        tag_92 = None

    issuer_cert_e_octets = _get_data_item(afl_data, b'\x9f\x32')  # 发卡行RSA公钥指数
    
    # 验证发卡行证书
    logger.debug("========验证发卡行证书========")
    issuer_cert_n_octets, issuer_cert_struct = restore_issuer_cert(
        tag_8f, tag_90, issuer_cert_e_octets, tag_92)
    if issuer_cert_struct is None:
        logger.error("发卡行证书结构解析错误")
        return False

    # 交叉检查数据
    issuer_id_hex = issuer_cert_struct["发卡行标识"].hex()
    for ind, ch in enumerate(issuer_id_hex):
        if ch == 'f':
            issuer_id = issuer_id_hex[0:ind]
            break
    else:
        issuer_id = issuer_id_hex

    the_pan = _parse_cn(_get_data_item(afl_data, b'\x5a'))
    if the_pan:
        assert the_pan.startswith(issuer_id), '应用主账号与发卡行标识不匹配'

    # 静态数据认证SDA
    logger.debug("========静态数据认证SDA========")
    sda_data = offcard_data['AFL']['SDA']
    sda_buffer = bytearray()
    for name, value in sda_data.items():
        sda_buffer.extend(bytes.fromhex(value))

    # 检查静态数据认证标签列表（标签9f4a），看AIP是否参与签名
    # JR/T 0025.7-2018 5.3.3.4 (P15), 5.4.3.1 (P25)
    # JR/T 0025.8-2018 9.4.2 (P21)
    if _in_data_set(afl_data, b'\x9f\x4a'):
        tag_9f4a = _get_data_item(afl_data, b'\x9f\x4a')
        if tag_9f4a != b'\x82':
            logger.error("静态数据认证标签列表存在，且包含非82的标签{}".format(tag_9f4a))  # JR/T 0025.7-2018 5.4.3.4 (P28)
        else:
            sda_buffer.extend(_get_data_item(gpo_resp, b'\x82'))
    sda_octets = bytes(sda_buffer)

    if _in_data_set(afl_data, b'\x93'):
        sda_signed = _get_data_item(afl_data, b'\x93')
        sda_struct = do_sda(issuer_cert_n_octets, issuer_cert_e_octets, sda_signed, sda_octets)
    else:
        logger.error("未找到签名的静态认证数据（标签93)")

    # 恢复IC卡证书
    tag_9f46 = _get_data_item(afl_data, b'\x9f\x46')  # IC卡RSA公钥证书
    tag_9f47 = _get_data_item(afl_data, b'\x9f\x47')  # IC卡RSA公钥指数
    tag_9f48 = _get_data_item(afl_data, b'\x9f\x48') if _in_data_set(afl_data, b'\x9f\x48') else None  # IC卡RSA公钥余数
    if tag_9f48 and len(tag_9f48) == 0:
        tag_9f48 = None

    iccard_cert_e_octets = tag_9f47

    iccard_cert_n_octets, iccard_cert_struct = restore_iccard_cert(
        issuer_cert_n_octets, issuer_cert_e_octets,
        tag_9f46, tag_9f48, tag_9f47, sda_octets)

    if iccard_cert_struct is None:
        logger.error("IC卡证书结构解析错误")
        return False

    # 交叉检查数据
    pan = _parse_cn(iccard_cert_struct["应用主账号"])
    assert the_pan == pan, '证书中的应用主账号（PAN）与其他数据中的不匹配'


    card_info = offcard_data['CARD_INFO']
    if card_info['Q_PBOC']:
        fdda = offcard_data['FDDA']
        # JR/T 0025.12-2018 7.5 (P21)
        # 动态签名可以在 GPO 响应中返回，也可以在 READ RECORD 命令中返回
        if _in_data_set(gpo_resp, b'\x9f\x4b'):
            tag_9f4b = _get_data_item(gpo_resp, b'\x9f\x4b')
        elif _in_data_set(afl_data, b'\x9f\x4b'):
            tag_9f4b = _get_data_item(afl_data, b'\x9f\x4b')
        else:
            logger.error(f'动态应用数据（9f4b）未找到')
            return

        dda_signed = tag_9f4b

        fdda_ver = int(fdda['VERSION'])
        # 验证签名的动态应用数据（fDDA）
        tag_9f37 = _get_data_item(gpo_pdol, b'\x9f\x37')
        tag_9f02 = _get_data_item(gpo_pdol, b'\x9f\x02')
        tag_5f2a = _get_data_item(gpo_pdol, b'\x5f\x2a')
        tag_9f69 = _get_data_item(afl_data, b'\x9f\x69')

        dda_struct = do_fdda(iccard_cert_n_octets, issuer_cert_e_octets, tag_9f4b, tag_9f37, tag_9f02, tag_5f2a, tag_9f69, fdda_ver)
    else:
        int_auth = offcard_data['INT_AUTH']
        ddol = bytes.fromhex(int_auth['INT_AUTH_DDOL'])
        resp = bytes.fromhex(int_auth['INT_AUTH_RESP'])
        do_dda(iccard_cert_n_octets, iccard_cert_e_octets, ddol, resp)


